"""
""" comment box 01
"""
  function! Sd_comment_01()
    if &ft == 'c'
      let l:comment = '//'
    elseif &ft == 'autohotkey'
      let l:comment = ';'
    elseif &ft == 'vim'
      let l:comment = '\"'
    else
      let l:comment = '#'
    endif
    let l:sd_match_res = matchstr(getline('.'), '^' . l:comment . '\s.*=\+$')
    if empty(l:sd_match_res)
      silent! exe ':s~\s*$~ ~|:s~^\s*~' . l:comment . ' ~'
      let l:space = repeat('=', 140 - strlen(getline('.')))
      call setline(line('.'), getline('.').l:space)
    else
      silent! exe ':s~=\+$~~'
      normal! xxV=
    endif
  endfunction

  function! Sd_comment_02()
    if &ft == 'c'
      let l:comment = '//'
    elseif &ft == 'autohotkey'
      let l:comment = ';'
    elseif &ft == 'vim'
      let l:comment = '"'
    else
      let l:comment = '#'
    endif
    let l:sd_match_res = matchstr(getline('.'), '^' . l:comment . '\s=\+')
    if empty(l:sd_match_res)
      silent! exe ':s~\s*$~~|:s~^\s*~ ~'
      let l:space = l:comment . ' ' .  repeat('=', 118 )
      call setline(line('.'), l:space . getline('.'))
    else
      silent! exe ':s~' . l:comment . '\s=\+~~'
      normal! V=
    endif
  endfunction

  nnoremap <silent> <localleader>m :call Sd_comment_02()<CR>

"""
""" comment box 02
"""
  let g:sd_comment_line = '======================================================================================'

  function! Sd_comment_box(mode)
    let l:sd_comment_line_present = 0
    if a:mode ==1
      let l:sd_match_res_up = matchstr(getline(line('.')-1), '^# =\+$')
      let l:sd_match_res_down = matchstr(getline(line('.')+1), '^# =\+$')
    else
      let l:sd_match_res_up = matchstr(getline(line("'<")), '^# =\+$')
      let l:sd_match_res_down = matchstr(getline(line("'>")), '^# =\+$')
    endif
    if !empty(l:sd_match_res_up) && !empty(l:sd_match_res_down)
      let l:sd_comment_line_present = 1
    endif

    if l:sd_comment_line_present == 1
      if a:mode == 1
        exe 'normal! kddjddk0xx'
      else
        let l:sd_vstart_linenumber=line("'<")
        let l:sd_vend_linenumber=line("'>")
        exe ':' . l:sd_vstart_linenumber . ',' . l:sd_vend_linenumber . 's/^# //'
        exe ' normal! g`>dd'
        exe ' normal! g`<dd'
      endif
    else
      if a:mode == 1
        exe 'normal! yyp'
        exe ':s/.*/' . g:sd_comment_line
        exe 'normal! kyyP'
        exe ':s/.*/' . g:sd_comment_line
        exe ':.,.+2 normal! 0i# '
      else
        let l:sd_vstart_linenumber=line("'<")
        let l:sd_vend_linenumber=line("'>") + 2
        exe ' normal! g`<'
        exe 'normal! yyP'
        exe ':s/.*/' . g:sd_comment_line
        exe ' normal! g`>'
        exe 'normal! yyp'
        exe ':s/.*/' . g:sd_comment_line
        exe ':' . l:sd_vstart_linenumber . ',' . l:sd_vend_linenumber . 's/^/# /'
      endif
    endif
  endfunction

  nnoremap <silent>  <localleader>N :cal Sd_comment_box(1)<cr>
  vnoremap  <silent> <localleader>N <Esc>:cal Sd_comment_box(2)<cr>

"""
""" triple comment
"""
  function! Sd_triple_comment() abort
    let begin = substitute(&commentstring, '\s*%.*', '', '')
    if getline('.') =~ '^' . begin.begin.begin
      while getline('.') =~ '^' . begin.begin.begin  && line('.') != 1
        normal! k
      endwhile
      if line('.') != 1
        normal! j
      endif
      normal! dW
      normal! 0jdW
      normal! 0jdW
    else
      " let @P = substitute(begin.begin.begin, '\n', '', 'g')
      let @p = begin.begin.begin
      exe "-1put P"
      exe "-1put P"
      normal! jJ
      put P
    endif
  endfunction

  nnoremap <silent> <localleader>n :call Sd_triple_comment()<CR>

"""
""" manually comment
"""
  function! Sd_manually_comment(lang) abort
    let v_start_line_num = line("'<")
    let v_end_line_num = line("'>")

    if a:lang == 'c'
      let comment = '//'
    elseif a:lang == 'autohotkey'
      let comment = ';'
    elseif a:lang == 'lua'
      let comment = '--'
    elseif a:lang == 'vim'
      let comment = '"'
    else
      let comment = '#'
    endif

    if &commentstring == ""
      if a:lang == 'c'
        setlocal commentstring=//\ %s
      elseif a:lang == 'autohotkey'
        setlocal commentstring=;\ %s
      elseif a:lang == 'lua'
        setlocal commentstring=--\ %s
      elseif a:lang == 'vim'
        setlocal commentstring=\"\ %s
      else
        setlocal commentstring=#\ %s
      endif
    endif

    let line_start_pattern = '^\s*' . comment . ' .*$'
    let g:t = line_start_pattern
    let comment_mark_present = 0
    if getline(v_start_line_num) =~ line_start_pattern && getline(v_end_line_num) =~ line_start_pattern
        let comment_mark_present = 1
    endif

    let count = v_end_line_num
    let smallest_line_col  = 888
    while count >= v_start_line_num
      if getline(count) !~ '^\s*$'
        let temp =  Sd_get_begin_whitespace(count)
        if smallest_line_col > temp
          let smallest_line_col  = temp
        endif
      endif
      let count -= 1
    endwhile

    if comment_mark_present == 0
      let count = v_end_line_num
      let g:t = smallest_line_col
      while count >= v_start_line_num
        if getline(count) !~ '^\s*$'
          call setline(count, strpart(getline(count), 0, smallest_line_col) . comment . ' ' . strpart(getline(count), smallest_line_col))
        endif
        let count -= 1
      endwhile
    else
      exe ':' . v_start_line_num . ',' . v_end_line_num . 's`' . comment . '\s\?`'
    endif
  endfunction

  function! Sd_html_manual_comment(mode) abort
    setlocal commentstring=<!--%s-->
    if a:mode == 0
      normal gcc
    else
      normal gvgc
    endif
  endfunction

  nnoremap <silent> <leader>ca V<esc>:call Sd_manually_comment('autohotkey')<CR>
  vnoremap <silent> <leader>ca <esc>:call Sd_manually_comment('autohotkey')<CR>
  nnoremap <silent> <leader>cv V<esc>:call Sd_manually_comment('vim')<CR>
  vnoremap <silent> <leader>cv <esc>:call Sd_manually_comment('vim')<CR>
  nnoremap <silent> <leader>cm V<esc>:call Sd_manually_comment('m')<CR>
  vnoremap <silent> <leader>cm <esc>:call Sd_manually_comment('m')<CR>
  nnoremap <silent> <leader>cc V<esc>:call Sd_manually_comment('c')<CR>
  vnoremap <silent> <leader>cc <esc>:call Sd_manually_comment('c')<CR>
  nnoremap <silent> <leader>c- V<esc>:call Sd_manually_comment('lua')<CR>
  vnoremap <silent> <leader>c- <esc>:call Sd_manually_comment('lua')<CR>

  nnoremap <silent> <leader>ch <esc>:call Sd_html_manual_comment(0)<CR>
  vnoremap <silent> <leader>ch <esc>:call Sd_html_manual_comment(1)<CR>

"""
""" quick insert/delete line number
"""
  function! Sd_insert_linenumber(mode)
    let l:sd_vstart_linenumber=line("'<")
    let l:sd_vend_linenumber=line("'>")
    let l:sd_total_linenumber =  l:sd_vend_linenumber - l:sd_vstart_linenumber + 1
    normal! `<
    let l:sd_linenumber_present = 1
    while line('.') <= l:sd_vend_linenumber
      if getline('.') !~ '^\s*\d\+\.'
        if getline('.') =~ '^\s*$'
          normal j
          continue
        endif
        let l:sd_linenumber_present = 0
        break
      endif
      if line('.') == line('$')
        break
      endif
      normal j
    endwhile

    normal! `<
    let l:smallest_line_col  = 888
    let l:empty_line_mark = 0
    while line('.') <= l:sd_vend_linenumber
      normal ^
      if getline('.') !~ '^\s*$'
        let l:temp =  col('.')
        if l:smallest_line_col > l:temp
          let l:smallest_line_col  = l:temp
        endif
      else
        let l:empty_line_mark = 1
      endif
      if line('.') == line('$')
        break
      endif
      normal j
    endwhile
    let l:final_spaces = repeat(' ', l:smallest_line_col - 1)

    normal! `<
    let l:sd_line_num = 1
    if  a:mode == 1
      if l:sd_linenumber_present == 0
        while l:sd_line_num <= l:sd_total_linenumber
          if l:empty_line_mark == 1
            let l:sd_tmp_str = ':s~^~\=printf("%' . strlen(l:sd_total_linenumber) . 'd. ", ' . l:sd_line_num . ')'
          else
            let l:sd_tmp_str = ':s~^\(' . l:final_spaces . '\)~\=printf("%s%' . strlen(l:sd_total_linenumber) . 'd. ", submatch(1), ' . l:sd_line_num . ')'
          endif
          exe l:sd_tmp_str
          normal j
          let l:sd_line_num += 1
        endwhile
      else
        exe ':' . l:sd_vstart_linenumber . ',' . l:sd_vend_linenumber . 's/\d\+\.//ge'
        exe ':nohl'
      endif
    else
      let l:sd_empty_lines = 0
      if l:sd_linenumber_present == 0
        while l:sd_line_num + l:sd_empty_lines <= l:sd_total_linenumber
          if getline('.')  =~ '^\s*$'
            let l:sd_empty_lines += 1
            normal j
            continue
          endif
          let l:sd_tmp_str = ':s~^\('. l:final_spaces .'\)~\=printf("%s%' . strlen(l:sd_total_linenumber) . 'd. ", submatch(1), ' . l:sd_line_num . ')'
          exe l:sd_tmp_str
          normal j
          let l:sd_line_num += 1
        endwhile
      else
        exe ':' . l:sd_vstart_linenumber . ',' . l:sd_vend_linenumber . 's/\d\+\.//ge'
        exe ':nohl'
      endif
    endif
    normal! `<
  endfunction

  function! Sd_input_line_number()
    let l:sd_vstart_linenumber=line("'<")
    let l:sd_vend_linenumber=line("'>")
    let l:sd_total_linenumber =  l:sd_vend_linenumber - l:sd_vstart_linenumber + 1

    normal! `<
    let l:smallest_line_col  = 888
    let l:empty_line_mark = 0
    while line('.') <= l:sd_vend_linenumber
      normal ^
      if getline('.') !~ '^\s*$'
        let l:temp =  col('.')
        if l:smallest_line_col > l:temp
          let l:smallest_line_col  = l:temp
        endif
      else
        let l:empty_line_mark = 1
      endif
      if line('.') == line('$')
        break
      endif
      normal j
    endwhile
    let l:final_spaces = repeat(' ', l:smallest_line_col - 1)

    normal! `<
    let l:left_algined_lines = []
    while line('.') <= l:sd_vend_linenumber
      normal ^
      if col('.') == l:smallest_line_col && getline('.') !~ '^\s*$'
        call add(l:left_algined_lines, line('.'))
      endif
      if line('.') == line('$')
        break
      endif
      normal j
    endwhile

    normal! `<
    let l:sd_linenumber_present = 1
    for l:num in l:left_algined_lines
      if getline(l:num) !~ '^\s*\d\+\.'
        let l:sd_linenumber_present = 0
        break
      endif
    endfor

    if l:sd_linenumber_present == 1
      " for l:num in l:left_algined_lines
      "   exe ':'. l:num .'s/\d\+\.//ge'
      "   exe ':nohl'
      " endfor
      let index = 0
      normal! `<
      while line('.') <= l:sd_vend_linenumber
        let index =  index(l:left_algined_lines, line('.'))
        if index == -1
          exe ':s~' .  repeat(' ', strlen(l:sd_total_linenumber)) . '~'
        else
          exe ':s/\d\+\.//ge'
        endif
        exe ':nohl'
        if line('.') == line('$')
          break
        endif
        normal j
      endwhile
    else
      let index = 0
      normal! `<
      while line('.') <= l:sd_vend_linenumber
        let index =  index(l:left_algined_lines, line('.'))
        if index == -1
          " let l:sd_tmp_str = ':s~^~' . l:final_spaces .  repeat(' ', strlen(l:sd_total_linenumber)) . '~'
          let l:sd_tmp_str = ':s~^' . l:final_spaces .'~' . l:final_spaces .  repeat(' ', strlen(l:sd_total_linenumber)) . '~'
        else
          let l:num = index + 1
          let l:sd_tmp_str = ':s~^\('. l:final_spaces .'\)~\=printf("%s%' . strlen(l:sd_total_linenumber) . 'd. ", submatch(1), ' . l:num . ')'
        endif
        silent! exe l:sd_tmp_str
        if line('.') == line('$')
          break
        endif
        normal j
      endwhile
    endif
  endfunction

  vnoremap <silent> <leader><leader>0 :<c-u>call Sd_input_line_number()<cr>
  vnoremap <silent> <leader><leader>- :<c-u>call Sd_insert_linenumber(1)<cr>
  vnoremap <silent> <leader><leader>= :<c-u>call Sd_insert_linenumber(2)<cr>

"""
""" quick paste content from named register
"""
  function! PasteFromNamedRegistor()
    let l:s = InputChar()
    if l:s =~ "\<esc>" || l:s =~ "\<c-c>" || l:s =~ '^\s*$'
      return
    endif

    if l:s == '\'
      let @0 = substitute(@0, '\n\?$', '\n', 'g')
      put 0
    elseif l:s == '0'
      silent! put +
    else
      exe 'normal! "'. l:s. 'p'
    endif
  endfunction

  nnoremap <silent> \ :<c-u>call PasteFromNamedRegistor()<cr>

"""
""" quick yank content to named register
"""
  function! Sd_yank_to_register(v_mode)
    let s = InputChar()
    if s =~ "\<esc>" || s =~ "\<c-c>" || s =~ '^\s*$'
      return
    endif

    if s == "\'"
      exe ':registers'
      return
    endif

    set noignorecase
    if a:v_mode == 1
      exe 'normal! "'. s. 'yy'
    else
      exe 'normal! gv' . '"' . s. 'y'
    endif
    set ignorecase
    let g:sd_notify = "copy to register " . s
    lua vim.notify(vim.g.sd_notify)
  endfunction

  nnoremap <silent> ' :<c-u>call Sd_yank_to_register(1)<cr>
  vnoremap <silent> ' :<c-u>call Sd_yank_to_register(2)<cr>

"""
""" quick shift to most left
"""
  function! Sd_quick_shift_to_most_left(mode)
    if a:mode == 0 " normal mode
      exe ':s`^\s\+``g'
    else  " visual mode
      let l:i = line("'<")
      let l:min_column = 999
      while l:i <= line("'>")
        if getline(l:i) =~ '^\s*$'
          let l:i = l:i + 1
          continue
        endif
        exe 'normal! '. l:i . 'G^'
        if l:min_column > col('.')
          let l:min_column = col('.')
        endif
        let l:i = l:i + 1
      endwhile
      let l:start_space = repeat(' ', l:min_column-1)
      exe ':' . line("'<") . ',' . line("'>") . 's`^'. l:start_space . '``'
    endif
  endfunction

  nnoremap <silent> <leader>< :call Sd_quick_shift_to_most_left(0)<CR>
  vnoremap <silent> <leader>< <ESC>:call Sd_quick_shift_to_most_left(1)<CR>

"""
""" clean whitespace under cursor
"""
  function! Sd_clean_whitespace_under_cursor()
    if Sd_get_charactor_under_cursor() != " "
      call Sd_echo("Error: cursor is not inside a whitespace!")
      return
    else
      while matchstr(getline('.'), '\%' . (col('.') - 1) . 'c.') == ' ' && col('.') != 1
        normal X
      endwhile
      normal dw
    endif
  endfunction

  nnoremap <silent> <space>c  :call Sd_clean_whitespace_under_cursor()<CR>

"""
""" delete file operation
"""
  function! Sd_delete_file(...)
    let l:file_name = expand('%')
    if a:0 ==1 && a:1 == 'forever'
      let l:user_input = input('Delete current file "'. expand('%') . '", and wipeout current buffer ? [y/n] ')
      if l:user_input == 'y' || l:user_input == 'Y'
        if delete(expand('%:p')) == 0
          exe ':bdelete!'
          echo ' >> delete and wipeout file "'. l:file_name . '" sucessfully'
        else
          call Sd_echo(' >> failed to delete and wipeout file "'. l:file_name .'"')
        endif
      else
        return
      endif
    else
      let l:user_input = input('Delete current file "'. expand('%') . '", but keep current buffer ? [y/n] ')
      if l:user_input == 'y' || l:user_input == 'Y'
        if delete(expand('%:p')) == 0
          " exe ':<C-u>'
          " echon ''
          echo ' >> delete file "'. l:file_name . '" from disk sucessfully'
          " echo 'delete file "'. l:file_name . '" from disk sucessfully'
          " exe "echo 'delete file \"'. l:file_name . '\" from disk sucessfully'"
        else
          call Sd_echo(' >> failed to delete file "'. l:file_name .'" from disk')
        endif
      else
        return
      endif
    endif
  endfunction

  nnoremap  <silent> <leader>DD :call Sd_delete_file()<CR>
  nnoremap  <silent> <leader>DF :call Sd_delete_file('forever')<CR>

"""
""" normalize indent
"""
  function! Sd_normalize_indent(...)
    exe ':retab'
    normal mP
    if a:0 >= 2
      let l:step = a:2
    else
      let l:step = &shiftwidth
    endif

    if a:0 >= 1 &&  a:1 == 'v'
      let l:ln_start =  line("'<") - 1
      let l:ln_end =  line("'>")
    else
      let l:ln_start = 0
      let l:ln_end = line('$')
      end
      while l:ln_start < l:ln_end
        let l:ln_start += 1
        if getline(line(l:ln_start)) !~ '^\s*$'
          continue
        else
          exe 'normal! '. l:ln_start . 'G^'
          if col('.') == 1 || (col('.') -1 ) % &shiftwidth == 0
            continue
          endif
          let l:final_whitespace_len = ((col('.') - 2) / &shiftwidth  + 1)  * &shiftwidth
          silent! exe ':s`^\s\+`' . repeat(' ', float2nr(l:final_whitespace_len))
        endif
      endwhile
      normal `P
  endfunction

  nnoremap  <silent> <leader>ci :call Sd_normalize_indent()<CR>
  vnoremap  <silent> <leader>ci <esc>:call Sd_normalize_indent('v')<CR>

"""
""" curl or browser
"""
  function! Sd_browser()
    if ! (has('win32') || has('win64'))
      call Sd_echo('not a window machine! You may use "QB" to tirgger "Sd_curl".')
      return
    endif
    let line0 = getline(".")
    let line = matchstr(line0, "http[^{} ]*")
    :if line==""
    let line = matchstr(line0, "ftp[^ ]*")
    :endif
    :if line==""
    let line = matchstr(line0, "file[^ ]*")
    :endif
    let line = escape(line, "#?&;|%")
    :if line==""
    let line = "\"" . (expand("%:p")) . "\""
    :endif
    exec ':silent !msedge.exe ' . line
  endfunction

  function! Sd_curl()
    if executable('curl') != 1
      call Sd_echo("no curl detected!")
    endif

    let line0 = getline(".")
    let url = matchstr(line0, "http[^ ]*")
    if url ==""
      call Sd_echo("no http(s) url detected!")
    else
      let t = 'set splitright | vnew | set filetype=sd-curl | read !curl -iksS -m 3 -L ' . url
      silent! exe t
      silent! exe "%s/\<c-m>//ge"
    endif
  endfunction

  nnoremap <silent> QB :call Sd_browser()<CR>
  nnoremap <silent> Qb :call Sd_curl()<CR>

"""
""" py auto docstring
"""
  function! Sd_sub_docstring_check_return(ln)
    let found_ret = 0
    let found_except = 0
    silent! normal! j
    while line('.') < line('$')
      if getline('.') =~ '^\s\+except'
        let found_except = 1
      endif
      if getline('.') =~ '^\s\+return'
        let found_ret = 1
        break
      elseif getline('.') =~ '^\s*\(async def\|def\|class\|if __name__\)'
        break
      endif
      silent! normal! j
    endwhile
    exe 'silent! normal! ' . a:ln . 'G'
    return [found_ret, found_except]
  endfunction

  function! Sd_autostring() abort
    let y_old = @"

    if &ft != 'python'
      call Sd_echo('not a python file!')
      return
    endif

    let found_mark = 0
    while line('.') > 1
      if getline('.') =~ '^\s*\(def\|async def\)\s'
        let found_mark = 1
        break
      endif
      normal! k
    endwhile

    if found_mark == 0
      return
    endif

    silent! normal! 0f(lyibb%

    let py_args_str =  substitute(@", '\_s\+', '', 'ge')
    silent! normal! l
    let [py_found_ret, py_found_except] = Sd_sub_docstring_check_return(line('.'))
    if Sd_get_charactor_under_cursor() == ':'
      if py_found_ret == 1
        let py_ret_str = '______'
      else
        let py_ret_str = 'None'
      endif
    else
      silent! normal! f>lyt:
      let py_ret_str = @"
    endif

    let  py_args = split(py_args_str, '\(\[\(\w\+,\?\)*\)\@<!,\(\s*\(\w\+,\?\)*\]\)\@!')
    if getline(line('.') + 1) =~ '^\s\+"""'
      return
    endif

    let @" = '"""' . "\n\n" . "Args:\n"
    for item in  py_args
      if  match(item, ':') >= 1
        let item =  split(item, ':')
        let item =  item[0] . ' ('. item[1]. ')'
      endif
      let @" = @". '    ' . item . ":\n"
    endfor

    let @" = @" . "\n" . "Returns:\n    " . py_ret_str

    if py_found_except == 1
      let @" = "\n" . @" . "\n\n" . "Raises:\n    ______"
    endif

    let @" = @" . "\n" . '"""'
    silent! put
    normal gpgb
    let @" = y_old
  endfunction

  function! Sd_auto_docstring_all() abort
    silent! normal! G
    while line('.') > 1
      if getline('.') =~ '^\s*\(async def\|def\)\s'
        silent! normal! mp
        call Sd_autostring()
        silent! normal! `pk
      endif
      silent! normal! k
    endwhile
  endfunction

  nnoremap <silent> QD :call Sd_autostring()<CR>
  nnoremap <silent> QA :call Sd_auto_docstring_all()<CR>

"""
""" process python long line
"""
  function! Sd_process_py_longline() abort
    silent! exe ':%s/\s\+$//e'
    normal! 0
    if getline('.') =~ '.*\\\s*$'
      while getline('.') =~ '.*\\\s*$'
        normal! $xJ
      endwhile
    else
      let count = 1
      while len(getline('.')) >= 80
        let count += 1
        if count >= 100
          call  Sd_echo('break from infinite loop!')
          return
        endif
        normal! 0
        normal! 79lbi\
        " exe 'normal! 79lbi\'
      endwhile
    endif
  endfunction

  nnoremap <silent> <leader>bp :call Sd_process_py_longline()<CR>

"""
""" quick insert unicode symbol
"""
  function! Sd_symbol_list(...)
    let symbol_list = [ "✅", "❎", "✓", "✗", "❌", "✔️ ", "ℹ️ ", "⚠️ ", "⚡", "⭐", "🌶️", "🍇", "🍌", "🍎", "🍏", "🍑", "🍒", "🍓", ]
    let list_to_display = map(copy(symbol_list), {idx, val -> 1 + idx . '. ' . val})
    let choice = inputlist(['Choose a filetype:'] + list_to_display)
    if choice <= 0 || choice > len(symbol_list)
      return
    endif
    let choice = symbol_list[choice -1]
    exe "normal! a" . choice . "\<esc>"
  endfunction

  nnoremap <silent> <leader>sm :call Sd_symbol_list()<CR>
  vnoremap <silent> <leader>sm <esc>:call Sd_symbol_list()<CR>
  inoremap <silent> <leader>sm <esc>:call Sd_symbol_list()<CR>

"""
""" sub-title * toggle
"""
  function! Sd_add_substitle02() abort
    if getline('.') =~ '^\s*•'
      normal! ^dw
    else
      " exe 's~\S~• &'
      exe 's~\S~● &'
    endif
  endfunction

  function! Sd_add_substitle01() abort
    if getline('.') =~ '^\s*\*'
      normal! ^dw
    else
      exe 's~\S~* &'
    endif
  endfunction

  nnoremap <silent> <leader>* :call Sd_add_substitle02()<CR>
  nnoremap <silent> * :call Sd_add_substitle01()<CR>

"""
""" DOS line endings to Linux line endings
"""
  " ctrl-v ctrl-m
  function! Sd_convert_chinese_char(code)
    silent exe ":set ff=unix fileformat=unix"
    silent exe ":retab"

    if a:code == "all"
      silent exe ":%s/\s\+$//e"
      silent exe ":%s/<c-v><c-m>/\r/ge"
      silent exe ":%s/。/\./ge"
      silent exe ":%s/，/,/ge"
      silent exe ":%s/；/,/ge"
      silent exe ":%s/？/?/ge"
      silent exe ":%s/：/\:/ge"
      silent exe ":%s/‘/\'/ge"
      silent exe ":%s/’/\'/ge"
      silent exe ":%s/”/\"/ge"
      silent exe ":%s/“/\"/ge"
      silent exe ":%s/《/\</ge"
      silent exe ":%s/》/\>/ge"
      silent exe ":%s/—/-/ge"
      silent exe ":%s/）/\)/ge"
      silent exe ":%s/（/\(/ge"
      silent exe ":%s/…/.../ge"
      silent exe ":%s/￥/$/ge"
      silent exe ":%s/！/!/ge"
      silent exe ":%s/·/`/ge"
      silent exe ":%s`、`,`ge"
      silent exe ":%s`　` `ge"
      " silent exe ":%s/    / /g"
      " special invisible characters
      silent exe ":%s` ``ge"
      silent exe ":%s`–`-`ge"
      silent exe ":%s/[^[:print:]]//ge"
    else
      silent exe ":%s/\s\+$//e"
      silent exe ":%s/<c-v><c-m>/\r/ge"
      silent exe ":'<,'>s/。/\./ge"
      silent exe ":'<,'>s/，/,/ge"
      silent exe ":'<,'>s/；/,/ge"
      silent exe ":'<,'>s/？/?/ge"
      silent exe ":'<,'>s/：/\:/ge"
      silent exe ":'<,'>s/‘/\'/ge"
      silent exe ":'<,'>s/’/\'/ge"
      silent exe ":'<,'>s/”/\"/ge"
      silent exe ":'<,'>s/“/\"/ge"
      silent exe ":'<,'>s/《/\</ge"
      silent exe ":'<,'>s/》/\>/ge"
      silent exe ":'<,'>s/—/-/ge"
      silent exe ":'<,'>s/）/\)/ge"
      silent exe ":'<,'>s/（/\(/ge"
      silent exe ":'<,'>s/…/.../ge"
      silent exe ":'<,'>s/￥/$/ge"
      silent exe ":'<,'>s/！/!/ge"
      silent exe ":'<,'>s/·/`/ge"
      silent exe ":'<,'>s`、`,`ge"
      silent exe ":'<,'>s`　` `ge"
      silent exe ":'<,'>s` ``ge"
      silent exe ":'<,'>s`–`-`ge"
      silent exe ":'<,'>s/[^[:print:]]//ge"
    endif
  endfunction

  nnoremap <silent> <leader>c<cr> :call Sd_convert_chinese_char("all")<CR>
  vnoremap <silent> <leader>c<cr> :call Sd_convert_chinese_char("selected")<CR>

